package main

import (
	"context"
	"flag"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/tencentyun/cos-go-sdk-v5"

	configpkg "github.com/liyixin123/my-cos-project/internal/config"
	fileclassifier "github.com/liyixin123/my-cos-project/internal/files"
)

// loadConfig wraps the shared configuration loader and logs non-fatal errors.
func loadConfig() *configpkg.Config {
	cfg, err := configpkg.Load()
	if err != nil {
		fmt.Fprintf(os.Stderr, "加载配置时出现问题: %v\n", err)
		return &configpkg.Config{}
	}
	return cfg
}

func main() {
	// 加载配置文件
	config := loadConfig()

	// 检查是否使用简化命令格式
	if len(os.Args) >= 3 && os.Args[1] == "upload" {
		// 简化的上传命令格式: ./cos_sdk_demo upload /path/to/file
		handleSimplifiedUpload(os.Args[2], config)
		return
	}

	// 定义命令行参数
	action := flag.String("action", "list", "Action to perform: list, upload, download")
	secretID := flag.String("secret-id", config.SecretID, "COS Secret ID")
	secretKey := flag.String("secret-key", config.SecretKey, "COS Secret Key")
	bucketName := flag.String("bucket", config.Bucket, "COS Bucket Name")
	region := flag.String("region", config.Region, "COS Region, e.g., ap-shanghai")
	key := flag.String("key", "", "Object key for upload/download")
	localFile := flag.String("file", "", "Local file path for upload/download")
	content := flag.String("content", "", "Content to upload (alternative to file)")
	dir := flag.String("dir", "", "Directory to list (empty for all directories)")

	flag.Parse()

	// 验证必要参数
	if *secretID == "" || *secretKey == "" || *bucketName == "" || *region == "" {
		fmt.Println("Error: Missing required COS credentials")
		fmt.Println("Please provide them via environment variables or command line arguments:")
		fmt.Println("  COS_SECRET_ID, COS_SECRET_KEY, COS_BUCKET, COS_REGION")
		flag.Usage()
		os.Exit(1)
	}

	// 初始化客户端
	u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", *bucketName, *region))
	b := &cos.BaseURL{BucketURL: u}
	client := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  *secretID,
			SecretKey: *secretKey,
		},
	})

	// 根据参数执行对应操作
	switch *action {
	case "list":
		listObjects(client, *dir)
	case "upload":
		if *key == "" {
			fmt.Println("Error: Missing object key for upload")
			flag.Usage()
			os.Exit(1)
		}

		if *localFile != "" {
			// 从文件上传
			uploadFileFromPath(client, *key, *localFile)
		} else if *content != "" {
			// 从字符串内容上传
			uploadFile(client, *key, *content)
		} else {
			fmt.Println("Error: Please provide either -file or -content for upload")
			flag.Usage()
			os.Exit(1)
		}
	case "download":
		if *key == "" {
			fmt.Println("Error: Missing object key for download")
			flag.Usage()
			os.Exit(1)
		}

		if *localFile != "" {
			// 下载到文件
			downloadFileToPath(client, *key, *localFile)
		} else {
			// 显示内容
			downloadFile(client, *key)
		}
	default:
		fmt.Printf("Error: Unknown action '%s'\n", *action)
		flag.Usage()
		os.Exit(1)
	}
}

// 处理简化的上传命令
func handleSimplifiedUpload(filePath string, config *configpkg.Config) {
	// 验证必要参数
	if config.SecretID == "" || config.SecretKey == "" || config.Bucket == "" || config.Region == "" {
		fmt.Println("Error: Missing required COS credentials in configuration")
		fmt.Println("Please set environment variables or create ~/.cos-config.json file")
		os.Exit(1)
	}

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		fmt.Printf("Error: File '%s' does not exist\n", filePath)
		os.Exit(1)
	}

	// 获取文件名并添加时间戳
	fileName := filepath.Base(filePath)
	fileExt := filepath.Ext(fileName)
	fileNameWithoutExt := fileName[:len(fileName)-len(fileExt)]
	objectKey := fileclassifier.GenerateRemotePath(filePath, "")

	// 初始化客户端
	u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", config.Bucket, config.Region))
	b := &cos.BaseURL{BucketURL: u}
	client := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  config.SecretID,
			SecretKey: config.SecretKey,
		},
	})

	// 上传文件
	file, err := os.Open(filePath)
	if err != nil {
		fmt.Printf("Error opening file %s: %v\n", filePath, err)
		os.Exit(1)
	}
	defer file.Close()

	_, err = client.Object.Put(context.Background(), objectKey, file, nil)
	if err != nil {
		fmt.Printf("Error uploading file: %v\n", err)
		os.Exit(1)
	}

	// 生成并显示可访问链接
	fileURL := fmt.Sprintf("https://%s.cos.%s.myqcloud.com/%s", config.Bucket, config.Region, objectKey)
	fmt.Printf("Successfully uploaded file to: %s\n", objectKey)

	// 生成并显示Markdown格式的图片链接
	markdownLink := fmt.Sprintf("![%s](%s)", fileNameWithoutExt, fileURL)
	fmt.Printf("Markdown Link: %s\n", markdownLink)
	fmt.Printf("[Upload Success]:\n%s\n", fileURL)
}

func listObjects(client *cos.Client, dir string) {
	// 定义所有已知目录
	allDirs := []string{"images", "documents", "audio", "videos", "archives", "code", "others"}

	// 如果指定了目录，只处理该目录
	var dirsToProcess []string
	if dir != "" {
		// 验证目录是否有效
		validDir := false
		for _, d := range allDirs {
			if d == dir {
				validDir = true
				break
			}
		}
		if !validDir {
			fmt.Printf("Error: Invalid directory '%s'. Valid directories are: %s\n",
				dir, strings.Join(allDirs, ", "))
			os.Exit(1)
		}
		dirsToProcess = []string{dir}
	} else {
		dirsToProcess = allDirs
	}

	totalFiles := 0
	hasAnyFiles := false

	// 处理每个目录
	for _, currentDir := range dirsToProcess {
		opt := &cos.BucketGetOptions{
			Prefix:  currentDir + "/",
			MaxKeys: 1000,
		}

		result, _, err := client.Bucket.Get(context.Background(), opt)
		if err != nil {
			fmt.Printf("Error listing objects in %s: %v\n", currentDir, err)
			continue
		}

		if len(result.Contents) > 0 {
			hasAnyFiles = true

			// 显示目录标题
			fmt.Printf("\n========== %s (%d files) ==========\n",
				strings.Title(currentDir), len(result.Contents))
			fmt.Printf("%-50s %-12s %s\n", "File Name", "Size (bytes)", "Last Modified")
			fmt.Println("----------------------------------------------------------------------")

			// 显示文件列表
			for _, content := range result.Contents {
				// 移除目录前缀，只显示文件名
				fileName := strings.TrimPrefix(content.Key, currentDir+"/")
				fmt.Printf("%-50s %-12d %s\n",
					fileName, content.Size, content.LastModified)
			}

			totalFiles += len(result.Contents)
		}
	}

	if !hasAnyFiles {
		if dir != "" {
			fmt.Printf("No files found in directory '%s'\n", dir)
		} else {
			fmt.Println("No files found in any directory")
		}
		return
	}

	// 显示总计
	fmt.Println("\n======================================================================")
	if dir != "" {
		fmt.Printf("Total files in '%s': %d\n", dir, totalFiles)
	} else {
		fmt.Printf("Total files in all directories: %d\n", totalFiles)
	}
}

func uploadFile(client *cos.Client, key, content string) {
	_, err := client.Object.Put(context.Background(), key,
		strings.NewReader(content), nil)
	if err != nil {
		fmt.Printf("Error uploading file: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("Successfully uploaded content to '%s'\n", key)
}

func uploadFileFromPath(client *cos.Client, key, filepath string) {
	file, err := os.Open(filepath)
	if err != nil {
		fmt.Printf("Error opening file %s: %v\n", filepath, err)
		os.Exit(1)
	}
	defer file.Close()

	_, err = client.Object.Put(context.Background(), key, file, nil)
	if err != nil {
		fmt.Printf("Error uploading file: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("Successfully uploaded file '%s' to '%s'\n", filepath, key)
}

func downloadFile(client *cos.Client, key string) {
	resp, err := client.Object.Get(context.Background(), key, nil)
	if err != nil {
		fmt.Printf("Error downloading file: %v\n", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("Error reading file content: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("Content of '%s':\n%s\n", key, string(data))
}

func downloadFileToPath(client *cos.Client, key, filepath string) {
	resp, err := client.Object.Get(context.Background(), key, nil)
	if err != nil {
		fmt.Printf("Error downloading file: %v\n", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	out, err := os.Create(filepath)
	if err != nil {
		fmt.Printf("Error creating file %s: %v\n", filepath, err)
		os.Exit(1)
	}
	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		fmt.Printf("Error writing to file: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Successfully downloaded '%s' to '%s'\n", key, filepath)
}
